package cn.yu_lu.utils;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

/**
 * 数据摘要工具类
 * @author zhang
 *
 */
public class DigestUtil {
	
	/**
	 * 按照给定的摘要算法名称将给定字符串进行数据摘要
	 * @param str	待计算摘要字符串
	 * @param type	摘要算法名称
	 * @return	摘要结果,当传入空字符串或算法名称为空时返回null
	 * @throws IllegalArgumentException 当传入非法的算法名称时抛出
	 */
	public static String digest(String str,String algorithm){
		if(JudgeUtil.hasBlank(str,algorithm)) return null;
		MessageDigest md5Digest=null;
		try {
			md5Digest = MessageDigest.getInstance(algorithm);
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException(e);
		}
		byte[] md5Data=null;
		try {
			md5Data = md5Digest.digest(str.getBytes("UTF-8"));
		} catch (UnsupportedEncodingException e) {
			throw new UnsupportedOperationException();
		}
		return ConvertUtil.toHex(md5Data);
	}

	/**
	 * 对给定的数据进行md2摘要
	 * @param str 待计算摘要字符串
	 * @return 摘要结果,当传入空字符串时返回null
	 */
	public static String md2(String str){
		if(JudgeUtil.isBlank(str)) return null;
		return digest(str,"MD2");
	}
	
	/**
	 * 对给定的数据进行md5摘要
	 * @param str 待计算摘要字符串
	 * @return 摘要结果,当传入空字符串时返回null
	 */
	public static String md5(String str){
		if(JudgeUtil.isBlank(str)) return null;
		return digest(str,"MD5");
	}
	
	/**
	 * 对给定的数据进行sha1摘要
	 * @param str 待计算摘要字符串
	 * @return 摘要结果,当传入空字符串时返回null
	 */
	public static String sha1(String str){
		if(JudgeUtil.isBlank(str)) return null;
		return digest(str,"SHA-1");
	}
	
	/**
	 * 对给定的数据进行sha256摘要
	 * @param str 待计算摘要字符串
	 * @return 摘要结果,当传入空字符串时返回null
	 */
	public static String sha256(String str){
		if(JudgeUtil.isBlank(str)) return null;
		return digest(str,"SHA-256");
	}
	
	/**
	 * 对给定的数据进行sha384摘要
	 * @param str 待计算摘要字符串
	 * @return 摘要结果,当传入空字符串时返回null
	 */
	public static String sha384(String str){
		if(JudgeUtil.isBlank(str)) return null;
		return digest(str,"SHA-384");
	}
	
	/**
	 * 对给定的数据进行sha512摘要
	 * @param str 待计算摘要字符串
	 * @return 摘要结果,当传入空字符串时返回null
	 */
	public static String sha512(String str){
		if(JudgeUtil.isBlank(str)) return null;
		return digest(str,"SHA-512");
	}
	
	/**
	 * 带密钥(MAC)的数据摘要
	 * @param str 待摘要计算字符串
	 * @param key 密钥
	 * @param algorithm 算法名称
	 * @return 摘要结果,当传入空字符串或密钥为空或算法为空时返回null
	 * @throws 当传入非法的算法名称或密钥时抛出
	 */
	public static String digest(String str,String key,String algorithm){
		if(JudgeUtil.hasBlank(str,key,algorithm)) return null;
		Mac mac=null;
		try {
			mac = Mac.getInstance(algorithm);
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException();
		}
		try {
			mac.init(new SecretKeySpec(ConvertUtil.hex2Bytes(key),mac.getAlgorithm()));
			return ConvertUtil.toHex(mac.doFinal(str.getBytes("UTF-8")));
		} catch (InvalidKeyException e) {
			throw new IllegalArgumentException();
		} catch (UnsupportedEncodingException e) {
			throw new UnsupportedOperationException();
		}
	}
	
	/**
	 * HMACMD5摘要计算
	 * @param str 待计算摘要字符串
	 * @param key 密钥
	 * @return 摘要结果，当传入空字符串或密钥为空时返回null
	 */
	public static String hmacMD5(String str,String key){
		if(JudgeUtil.isBlank(str)) return null;
		return digest(str,key,"HmacMD5");
	}
	
	/**
	 * HMACSHA1摘要计算
	 * @param str 待计算摘要字符串
	 * @param key 密钥
	 * @return 摘要结果，当传入空字符串或密钥为空时返回null
	 */
	public static String hmacSHA1(String str,String key){
		if(JudgeUtil.isBlank(str)) return null;
		return digest(str,key,"HmacSHA1");
	}
	
	/**
	 * HMACSHA256摘要计算
	 * @param str 待计算摘要字符串
	 * @param key 密钥
	 * @return 摘要结果，当传入空字符串或密钥为空时返回null
	 */
	public static String hmacSHA256(String str,String key){
		if(JudgeUtil.isBlank(str)) return null;
		return digest(str,key,"HmacSHA256");
	}
}
